home *** CD-ROM | disk | FTP | other *** search
- /*
- File: BasicDiskImage.c
-
- Contains: Puts the contents of a disk in a file.
-
- Written by: Q
-
- Copyright: Copyright © 1999 by Apple Computer, Inc., All Rights Reserved.
-
- You may incorporate this Apple sample source code into your program(s) without
- restriction. This Apple sample source code has been provided "AS IS" and the
- responsibility for its operation is yours. You are not permitted to redistribute
- this Apple sample source code as "Apple sample source code" after having made
- changes. If you're going to re-distribute the source, we require that you make
- it clear in the source that the code was descended from Apple sample source
- code, but that you've made changes.
-
- Change History (most recent first):
-
- */
-
- /////////////////////////////////////////////////////////////////
-
- // MIB Setup
-
- #include "MoreSetup.h"
-
- // Mac OS Interfaces
-
- #include <Files.h>
- #include <Devices.h>
- #include <MacMemory.h>
- #include <Navigation.h>
- #include <StandardFile.h>
-
- // Standard C interfaces
-
- #include <stdio.h>
- #include <stdlib.h>
-
- // MoreIsBetter Interfaces
-
- #include "MoreDisks.h"
-
- /////////////////////////////////////////////////////////////////
-
- static void SetWidePosOffset(UInt32 blockOffset, XIOParamPtr pb)
- // Set up ioPosMode and either ioPosOffset or ioWPosOffset for a
- // device _Read or _Write.
- //
- // Code stolen from Technote 1189.
- {
- pb->ioWPosOffset.lo = blockOffset << 9; // convert block number
- pb->ioWPosOffset.hi = blockOffset >> 23; // to wide byte offset
-
- if ( pb->ioWPosOffset.hi != 0 ) {
- // Offset on drive is >= 4G, so use wide positioning mode
- pb->ioPosMode = fsFromStart | (1 << kWidePosOffsetBit);
- } else {
- // Offset on drive is < 4G, so use regular positioning mode,
- // and move the offset into ioPosOffset
- pb->ioPosMode = fsFromStart;
- ((IOParam *)pb)->ioPosOffset = pb->ioWPosOffset.lo;
- }
- }
-
- /////////////////////////////////////////////////////////////////
-
- enum {
- kBufferSize = 1024L * 1024L // Do the copy in 1 MB chunks.
- };
-
- static OSStatus ImageDiskToFile(SInt16 driveNumber, UInt32 startBlock, UInt32 numBlocks, const FSSpec *fss)
- // Creates a file at fss containing the contents of blocks [startBlock..startBlock + numBlocks)
- // of the drive specified by driveNumber.
- {
- OSStatus err;
- OSStatus junk;
- Ptr bufferPtr;
- SInt16 fileRefNum;
- XIOParam pb;
- UInt32 thisBlock;
- UInt32 lastBlock;
- UInt32 blocksThisTime;
- SInt32 bytesToWrite;
-
- bufferPtr = nil;
- fileRefNum = 0;
-
- // Create and open the file, and then allocate our memory buffer.
-
- junk = FSpCreate(fss, 'hDmp', 'BINA', 0);
- err = FSpOpenDF(fss, fsWrPerm, &fileRefNum);
- if (err == noErr) {
- bufferPtr = NewPtr(kBufferSize);
- err = MemError();
- }
- if (err == noErr) {
-
- // Set up constant parts of param block.
-
- pb.ioRefNum = MoreGetDriveRefNum(driveNumber);
- pb.ioVRefNum = driveNumber;
- pb.ioBuffer = bufferPtr;
- pb.ioPosMode = fsFromStart;
-
- // Loop, reading blocks from the disk and writing them to the file until we're out of blocks.
-
- thisBlock = startBlock;
- lastBlock = startBlock + numBlocks;
- while ( (err == noErr) && (thisBlock != lastBlock) ) {
- if ( (lastBlock - thisBlock) > (kBufferSize / 512) ) {
- blocksThisTime = (kBufferSize / 512);
- } else {
- blocksThisTime = (lastBlock - thisBlock);
- }
- pb.ioReqCount = blocksThisTime * 512;
- SetWidePosOffset(thisBlock, &pb);
- err = PBReadSync( (ParmBlkPtr) &pb);
- if (err == noErr) {
- bytesToWrite = blocksThisTime * 512;
- err = FSWrite(fileRefNum, &bytesToWrite, bufferPtr);
- }
- if (err == noErr) {
- thisBlock += blocksThisTime;
-
- // Show some progress.
-
- printf(".");
- fflush(stdout);
- }
- }
- }
-
- // Clean up.
-
- if ( fileRefNum != 0 ) {
- junk = FSClose(fileRefNum);
- MoreAssertQ(junk == noErr);
- }
- if (bufferPtr != nil) {
- DisposePtr(bufferPtr);
- MoreAssertQ(MemError() == noErr);
- }
-
- return err;
- }
-
- /////////////////////////////////////////////////////////////////
-
- static void DoListDriveQueue(void)
- // Prints a list of drives and their sizes. Stolen from the test
- // code for the MoreDisks module of MoreIsBetter.
- {
- SInt16 index;
- DrvQElPtr thisDrv;
- UInt32 sizeInBlocks;
- MoreDisksCDROMResponse isCDResponse;
- char cdChar;
-
- printf("List of drives:\n");
- printf("DrvNum Size\n");
- index = 1;
- do {
- thisDrv = MoreGetIndDrive(index);
- if (thisDrv != nil) {
- if ( MoreGetDriveSize(thisDrv->dQDrive, &sizeInBlocks) != noErr ) {
- sizeInBlocks = 0;
- }
- MoreIsDriveCDROM(thisDrv->dQDrive, &isCDResponse);
- switch (isCDResponse) {
- case kMoreDriveUnableToDetermineCDROM: cdChar = '?'; break;
- case kMoreDriveIsCDROM: cdChar = 'C'; break;
- case kMoreDriveIsNotCDROM: cdChar = 'N'; break;
- default:
- MoreAssertQ(false);
- break;
- }
-
- printf("%6d %8ld (%c)\n", thisDrv->dQDrive, sizeInBlocks, cdChar);
- index += 1;
- }
- } while (thisDrv != nil);
- }
-
- /////////////////////////////////////////////////////////////////
-
- // I wrote all the code to allow the user to choose where to save the
- // file using Nav, then remembered that I wanted to be able to run this
- // program even on systems that don't have Nav. So it was back to Standard
- // File.
-
- #if 0
-
- static OSStatus NavExtractSingleReply(const NavReplyRecord *reply, FSSpec *fss)
- {
- OSStatus err;
- SInt32 itemCount;
- AEKeyword junkKeyword;
- DescType junkDescType;
- Size junkSize;
-
- MoreAssertQ( (AECountItems(&reply->selection, &itemCount) == noErr) && (itemCount == 1));
-
- err = AEGetNthPtr(&reply->selection,
- 1,
- typeFSS,
- &junkKeyword,
- &junkDescType,
- fss,
- sizeof(*fss),
- &junkSize);
- if (err == noErr) {
- MoreAssertQ(junkDescType == typeFSS);
- MoreAssertQ(junkSize == sizeof(*fss));
-
- // If Nav gave us a bogus FSSpec, fix it.
-
- if ( fss->name[0] == 0 ) {
- (void) FSMakeFSSpec(fss->vRefNum, fss->parID, fss->name, fss);
- }
- }
- return err;
- }
-
- {
- NavReplyRecord reply;
- NavDialogOptions options;
-
- err = NavGetDefaultDialogOptions(&options);
- if (err == noErr) {
- err = NavPutFile(nil, &reply, &options, nil, 'BINA', 'hDmp', nil);
- if (err == noErr) {
- err = NavExtractSingleReply(&reply, &fss);
- }
- junk = NavDisposeReply(&reply);
- MoreAssertQ(junk == noErr);
- }
- }
-
- #endif
-
- /////////////////////////////////////////////////////////////////
-
- void main(void)
- // The main entry point. Ask the user to choose a disk, select
- // a section of the disk to save, and then choose a file for
- // where to place the disk image.
- {
- OSStatus err;
- char tmpStr[256];
- SInt16 driveNum;
- UInt32 sizeInBlocks;
- UInt32 startBlock;
- UInt32 blocksToRead;
- FSSpec fss;
-
- printf("BasicDiskImage\n");
- printf("-- A program to copy the entire contents of a disk to a file.\n");
-
- DoListDriveQueue();
-
- printf("Enter a drive number:\n");
- gets(tmpStr);
- driveNum = atol(tmpStr);
-
- err = MoreGetDriveSize(driveNum, &sizeInBlocks);
- if (err == noErr) {
- printf("Enter the first block number to image (return for 0).\n");
- gets(tmpStr);
- if (tmpStr[0] == 0) {
- startBlock = 0;
- } else {
- startBlock = atol(tmpStr);
- }
- if (startBlock >= sizeInBlocks) {
- printf("startBlock must be less than sizeInBlocks.\n");
- err = userCanceledErr;
- }
- }
- if (err == noErr) {
- printf("Enter the number of blocks to image (return for all).\n");
- gets(tmpStr);
- if (tmpStr[0] == 0) {
- blocksToRead = sizeInBlocks - startBlock;
- } else {
- blocksToRead = atol(tmpStr);
- }
- if (blocksToRead > sizeInBlocks) {
- printf("blocksToRead must be less than sizeInBlocks.\n");
- err = userCanceledErr;
- }
- if ((startBlock + blocksToRead) > sizeInBlocks) {
- printf("startBlock + blocksToRead must be less than or equal to sizeInBlocks.\n");
- err = userCanceledErr;
- }
- }
- if (err == noErr) {
- StandardFileReply reply;
-
- StandardPutFile("\pSave a basic disk image:", "\pBasic Disk Image", &reply);
- if (reply.sfGood) {
- fss = reply.sfFile;
- if (reply.sfReplacing) {
- err = FSpDelete(&fss);
- }
- } else {
- err = userCanceledErr;
- }
- }
- if (err == noErr) {
- err = ImageDiskToFile(driveNum, startBlock, blocksToRead, &fss);
- printf("\n");
- }
-
- if (err == noErr) {
- printf("Success.\n");
- } else {
- printf("Failed with error %ld.\n", err);
- }
-
- printf("Done. Press command-Q to Quit.\n");
- }